/******************************************************************************
** 公司名称：天津柯迪斯科技有限公司
** 版权信息：
** 文件名称： bsp_RTC.c
** 模块名称： KD986_New仪表时钟RTC模块
** 版 本 号： V1.0
** 作    者： 蒲磊
**
** 修改记录： 版本     修改人      时间         修改内容
**
******************************************************************************/

/******************************************************************************
* 头文件
******************************************************************************/
#include "bsp_RTC.h"
/******************************************************************************
* 本文件宏定义 ('#define')
******************************************************************************/

/******************************************************************************
* 本文件类型定义 ('typedef')
******************************************************************************/

/******************************************************************************
* 本文件静态函数声明 ('static')
******************************************************************************/
static uint8_t RTC_Week_Get(uint16_t year, uint8_t month, uint8_t day);

/******************************************************************************
* 全局变量定义
******************************************************************************/
/* monthly correction data sheet */
const uint8_t table_week[12] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};

/* monmonth data table of common year */
const uint8_t mon_table[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
/*****************************************************************************
* 函数实现 - global ('extern') and local ('static')
******************************************************************************/


/******************************************************************************
** 功  能：RTC外设初始化
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vBsp_RTC_Init(void)
{
    calendar_type calendar;
    /* enable pwc and bpr clocks */
    crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_BPR_PERIPH_CLOCK, TRUE);

    /* enable the battery-powered domain write operations */
    pwc_battery_powered_domain_access(TRUE);

    /* check if rtc is initialized */
    if(bpr_data_read(BPR_DATA1) != 0x1234)
    {
        /*默认日期：2022-01-01 00：00：00*/
        calendar.year  = 2022;
        calendar.month = 1;
        calendar.date	= 1;
        calendar.hour	= 0;
        calendar.min	= 0;
        calendar.sec	= 0;

        /* reset battery-powered domain register */
        bpr_reset();

        /* enable the lext osc */
        crm_clock_source_enable(CRM_CLOCK_SOURCE_LEXT, TRUE);
        /* wait lext is ready */
        while(crm_flag_get(CRM_LEXT_STABLE_FLAG) == RESET);
        /* select the rtc clock source */
        crm_rtc_clock_select(CRM_RTC_CLOCK_LEXT);

        /* enable rtc clock */
        crm_rtc_clock_enable(TRUE);

        /* wait for rtc registers update */
        rtc_wait_update_finish();

        /* wait for the register write to complete */
        rtc_wait_config_finish();

        /* set rtc divider: set rtc period to 1sec */
        rtc_divider_set(32767);

        /* wait for the register write to complete */
        rtc_wait_config_finish();

        /* set time */
        ucRTC_Time_Set(&calendar);

        /* writes data to bpr register */
        bpr_data_write(BPR_DATA1, 0x1234);

    }
    else
    {
        /* wait for rtc registers update */
        rtc_wait_update_finish();

        /* wait for the register write to complete */
        rtc_wait_config_finish();

    }
}



/******************************************************************************
** 功  能：判断是闰年还是平年
** 参  数：年份
** 返回值：0-平年，1-闰年
** 备  注：- month       1  2  3  4  5  6  7  8  9  10 11 12
**         - leap year   31 29 31 30 31 30 31 31 30 31 30 31
**         - common year 31 28 31 30 31 30 31 31 30 31 30 31
******************************************************************************/
uint8_t ucRTC_Is_Leap_Year(uint16_t year)
{
    if(year % 4 == 0)
    {
        if(year % 100 == 0)
        {
            if(year % 400 == 0)
            {
                return 1;
            }
            else
            {
                return 0;
            }
        }
        else
        {
            return 1;
        }
    }
    else
    {
        return 0;
    }
}


/******************************************************************************
** 功  能：设置RTC日期及时间
** 参  数：calendar-日期结构体指针
** 返回值：0-设置成功，1-失败
** 备  注：the time basic : 1970.1.1
**         legitimate year: 1970 ~ 2099
******************************************************************************/
uint8_t ucRTC_Time_Set(calendar_type *calendar)
{
    uint32_t t;
    uint32_t seccount = 0;

    if(calendar->year < 1970 || calendar->year > 2099)
    {
        return 1;
    }

    for(t = 1970; t < calendar->year; t++)
    {
        if(ucRTC_Is_Leap_Year(t))
        {
            seccount += 31622400;
        }
        else
        {
            seccount += 31536000;
        }
    }

    calendar->month -= 1;

    for(t = 0; t < calendar->month; t++)
    {
        seccount += (uint8_t)mon_table[t] * 86400;

        if(ucRTC_Is_Leap_Year(calendar->year) && t == 1)
        {
            seccount += 86400;
        }
    }

    seccount += (uint8_t)(calendar->date - 1) * 86400;

    seccount += (uint8_t)calendar->hour * 3600;

    seccount += (uint8_t)calendar->min * 60;

    seccount += calendar->sec;

    /* enable pwc and bpr clocks */
    crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_BPR_PERIPH_CLOCK, TRUE);

    /* enable write access to bpr domain */
    pwc_battery_powered_domain_access(TRUE);

    /* set the rtc counter value */
    rtc_counter_set(seccount);

    /* wait for the register write to complete */
    rtc_wait_config_finish();

    return 0;
}


/******************************************************************************
** 功  能：设置RTC闹钟时间
** 参  数：calendar-日期结构体指针
** 返回值：0-设置成功，1-失败
** 备  注：the time basic : 1970.1.1
**         legitimate year: 1970 ~ 2099
******************************************************************************/
uint8_t RTC_Alarm_Clock_Set(calendar_type *calendar)
{
    uint16_t t;
    uint32_t seccount = 0;

    if(calendar->year < 1970 || calendar->year > 2099)
    {
        return 1;
    }

    for(t = 1970; t < calendar->year; t++)
    {
        if(ucRTC_Is_Leap_Year(t))
        {
            seccount += 31622400;
        }
        else
        {
            seccount += 31536000;
        }
    }

    calendar->month -= 1;

    for(t = 0; t < calendar->month; t++)
    {
        seccount += (uint8_t)mon_table[t] * 86400;

        if(ucRTC_Is_Leap_Year(calendar->year) && t == 1)
        {
            seccount += 86400;
        }
    }

    seccount += (uint8_t)(calendar->date - 1) * 86400;
    seccount += (uint8_t)calendar->hour * 3600;
    seccount += (uint8_t)calendar->min * 60;
    seccount += calendar->sec;

    /* enable pwc and bpr clocks */
    crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_BPR_PERIPH_CLOCK, TRUE);

    /* enable write access to bpr domain */
    pwc_battery_powered_domain_access(TRUE);

    /* set the rtc counter value */
    rtc_alarm_set(seccount);

    /* wait for the register write to complete */
    rtc_wait_config_finish();

    return 0;
}


/******************************************************************************
** 功  能：根据当前日期计算星期
** 参  数：year-年份，month-月，day-日
** 返回值：星期数
** 备  注：0代表星期天
******************************************************************************/
static uint8_t RTC_Week_Get(uint16_t year, uint8_t month, uint8_t day)
{
    uint16_t temp2;
    uint8_t yearh, yearl;

    yearh = year / 100;
    yearl = year % 100;

    if(yearh > 19)
    {
        yearl += 100;
    }

    temp2 = yearl + yearl / 4;
    temp2 = temp2 % 7;
    temp2 = temp2 + day + table_week[month - 1];

    if(yearl % 4 == 0 && month < 3)
    {
        temp2--;
    }

    return(temp2 % 7);
}

/******************************************************************************
** 功  能：获取RTC日期及时间
** 参  数：calendar-日期结构体指针
** 返回值：无
** 备  注：
******************************************************************************/
void RTC_Time_Get(calendar_type *calendar)
{
    static uint16_t daycnt = 0;
    uint32_t timecount = 0;
    uint32_t temp = 0;
    uint32_t temp1 = 0;
    static calendar_type calendar_temp;

    timecount = rtc_counter_get();
    temp = timecount / 86400;

    if(daycnt != temp)
    {
        daycnt = temp;
        temp1 = 1970;

        while(temp >= 365)
        {
            if(ucRTC_Is_Leap_Year(temp1))
            {
                if(temp >= 366)
                {
                    temp -= 366;
                }
                else
                {
                    temp1++;
                    break;
                }
            }
            else
            {
                temp -= 365;
            }

            temp1++;
        }

        calendar_temp.year = temp1;
        temp1 = 0;

        while(temp >= 28)
        {
            if(ucRTC_Is_Leap_Year(calendar_temp.year) && temp1 == 1)
            {
                if(temp >= 29)
                {
                    temp -= 29;
                }
                else
                {
                    break;
                }
            }
            else
            {
                if(temp >= mon_table[temp1])
                {
                    temp -= mon_table[temp1];
                }
                else
                {
                    break;
                }
            }

            temp1++;
        }

        calendar_temp.month = temp1 + 1;
        calendar_temp.date = temp + 1;
    }

    temp = timecount % 86400;
    calendar->year = calendar_temp.year;
    calendar->month = calendar_temp.month;
    calendar->date = calendar_temp.date;
    calendar->hour = temp / 3600;
    calendar->min = (temp % 3600) / 60;
    calendar->sec = (temp % 3600) % 60;
    calendar->week = RTC_Week_Get(calendar->year, calendar->month, calendar->date);
}
